/*
* Author: Chris Seguin
*
* This software has been developed under the copyleft
* rules of the GNU General Public License. Please
* consult the GNU General Public License for more
* details about use and distribution of this software.
*/
package org.acm.seguin.parser.query;
import java.util.Enumeration;
import org.acm.seguin.parser.Node;
import org.acm.seguin.parser.ast.ASTAdditiveExpression;
import org.acm.seguin.parser.ast.ASTEqualityExpression;
import org.acm.seguin.parser.ast.ASTMultiplicativeExpression;
import org.acm.seguin.parser.ast.ASTRelationalExpression;
import org.acm.seguin.parser.ast.ASTShiftExpression;
/**
* Performs a search on the parse tree to find specific nodes.
*
*@author Chris Seguin
*/
public class Search {
private EqualTree equalTree;
/**
* Constructor for the Search object
*/
public Search()
{
equalTree = new EqualTree();
}
/**
* This is the main program for this search. The inputs are the root node
* and what it is that we are searching for.
*
*@param root Description of Parameter
*@param lookingFor Description of Parameter
*@return Description of the Returned Value
*/
public Found search(Node root, Node lookingFor)
{
//System.out.println("DEBUG[Search.search] #1");
int last = root.jjtGetNumChildren();
int lookingForLast = lookingFor.jjtGetNumChildren();
if (last >= lookingForLast) {
Found result = searchAtLevel(root, lookingFor, last - lookingForLast);
if (result != null) {
return result;
}
}
for (int ndx = 0; ndx < last; ndx++) {
Found found = search(root.jjtGetChild(ndx), lookingFor);
if (found != null) {
return found;
}
}
return null;
}
/**
* Search at the level we are on. This will search on the level we are at
* trying to find the items in the lookingFor node. If it is found, a Found
* object is returned.
*
*@param root Description of Parameter
*@param lookingFor Description of Parameter
*@param stop Description of Parameter
*@return Description of the Returned Value
*/
private Found searchAtLevel(Node root, Node lookingFor, int stop)
{
//System.out.println("DEBUG[Search.searchAtLevel] #1");
for (int ndx = 0; ndx <= stop; ndx++) {
Node attempt = root.jjtGetChild(ndx);
Node lookingForNode = lookingFor.jjtGetChild(0);
//System.out.println("DEBUG[Search.searchAtLevel] #2 " + attempt.getClass().getName() + " " + lookingForNode.getClass().getName());
Boolean same = (Boolean) attempt.jjtAccept(equalTree, lookingForNode);
if (same.equals(Boolean.TRUE) && findAll(root, lookingFor, ndx)) {
//System.out.println("DEBUG[Search.searchAtLevel] #2");
return new Found(root, ndx);
}
}
//System.out.println("DEBUG[Search.searchAtLevel] #3");
return null;
}
/**
* Now that we have a guess where to find all the nodes, we do a thorough
* search. This function will return true if the other items all are found
* as children
*
*@param root Description of Parameter
*@param lookingFor Description of Parameter
*@param offset Description of Parameter
*@return Description of the Returned Value
*/
private boolean findAll(Node root, Node lookingFor, int offset)
{
//System.out.println("DEBUG[Search.findAll] #1");
for (int ndx = 1; ndx < lookingFor.jjtGetNumChildren(); ndx++) {
Node attempt = root.jjtGetChild(ndx + offset);
Boolean same = (Boolean) attempt.jjtAccept(equalTree, lookingFor.jjtGetChild(ndx));
if (same.equals(Boolean.FALSE)) {
//System.out.println("DEBUG[Search.findAll] #2");
return false;
}
}
//System.out.println("DEBUG[Search.findAll] #3");
return specialCase(root, lookingFor, offset);
}
/**
* Certain node types also have names associated with them. These nodes are
* mathematical operations such as * or / and < < or >>. We need to check in
* the instance that we have such a node that the names all match up. This
* method does that computation.
*
*@param root Description of Parameter
*@param lookingFor Description of Parameter
*@param offset Description of Parameter
*@return Description of the Returned Value
*/
private boolean specialCase(Node root, Node lookingFor, int offset)
{
//System.out.println("DEBUG[Search.specialCase] #1");
Enumeration enum1 = null;
Enumeration enum2 = null;
if (root instanceof ASTAdditiveExpression) {
enum1 = ((ASTAdditiveExpression) root).getNames();
enum2 = ((ASTAdditiveExpression) lookingFor).getNames();
}
else if (root instanceof ASTEqualityExpression) {
enum1 = ((ASTEqualityExpression) root).getNames();
enum2 = ((ASTEqualityExpression) lookingFor).getNames();
}
else if (root instanceof ASTMultiplicativeExpression) {
enum1 = ((ASTMultiplicativeExpression) root).getNames();
enum2 = ((ASTMultiplicativeExpression) lookingFor).getNames();
}
else if (root instanceof ASTRelationalExpression) {
enum1 = ((ASTRelationalExpression) root).getNames();
enum2 = ((ASTRelationalExpression) lookingFor).getNames();
}
else if (root instanceof ASTShiftExpression) {
enum1 = ((ASTShiftExpression) root).getNames();
enum2 = ((ASTShiftExpression) lookingFor).getNames();
}
//System.out.println("DEBUG[Search.specialCase] #2");
// We don't need to special case this node then
if (enum1 == null) {
return true;
}
// Skip the unnecessary ones
for (int ndx = 0; ndx < offset; ndx++) {
enum1.nextElement();
}
//System.out.println("DEBUG[Search.specialCase] #3");
// Compare the names
while (enum2.hasMoreElements()) {
Object value1 = enum1.nextElement();
Object value2 = enum2.nextElement();
if (!value1.equals(value2)) {
//System.out.println("DEBUG[Search.specialCase] #4");
return false;
}
}
// All the names are the same, we are done
//System.out.println("DEBUG[Search.specialCase] #5");
return true;
}
}